package com.example.calculation;

import com.example.entity.Ingredient;
import com.example.entity.OfficialGameData;
import com.example.entity.Recipe;

import java.util.List;
import java.util.Map;

public class IngredientLimit implements Cloneable{


    int[] materialCount = new int[47];
    int[] extraLimit = {0, 0, 0, 0, 0, 0};

    /**
     * 缓存 不同剩余材料量时，每种菜可以做的份数
     */
    private final static int[][] cacheResult = new int[1000][50];

    static {
        for (int i = 0; i < cacheResult.length; i++) {
            for (int j = 1; j < cacheResult[i].length; j++) {
                cacheResult[i][j] = i / j;
            }
        }
    }

    public IngredientLimit() {
        this(Integer.MAX_VALUE);
    }

    public IngredientLimit(int ingredientNum) {
        for (int i = 0; i < materialCount.length; i++) {
            materialCount[i] = ingredientNum;
        }
    }

    public IngredientLimit(int[] m) {
        if (m.length >= 47) {
            this.materialCount = m;
        } else {
            for (int i = 0; i < materialCount.length; i++) {
                materialCount[i] = 50;
            }
        }
    }


    public IngredientLimit(OfficialGameData officialGameData, Map<String, Integer> IngredientNum) {
        List<Ingredient> materials = officialGameData.getMaterials();
        for (Ingredient material : materials) {
            Integer integer = IngredientNum.get(material.getName());
            if (integer != null) {
                materialCount[material.getMaterialId()] = integer;
            } else {
                materialCount[material.getMaterialId()] = Integer.MAX_VALUE;
            }
        }
    }

    public int cookingQuanttiy(Recipe recipe) {
        int limit = recipe.getLimit() + extraLimit[recipe.getRarity()];
        return cookingQuanttiyAndReduce(recipe.getMaterials().toArray(new Recipe.Material[]{}), limit, materialCount);
    }

    public int cookingQuanttiy(Recipe recipe, int expected) {
        int limit = recipe.getLimit() + extraLimit[recipe.getRarity()];
        expected = expected < limit ? expected : limit;
        return cookingQuanttiyAndReduce(recipe.getMaterials().toArray(new Recipe.Material[]{}), expected, materialCount);
    }


    public static int cookingQuanttiy(Recipe.Material[] materials, int expected, int[] materialCount) {
        int max = expected, t;
        int length = materials.length;
        for (int i = 0; i < length; i++) {
            Recipe.Material material = materials[i];
            t = cacheResult[materialCount[material.material]][material.quantity];
            max = t < max ? t : max;
        }
        return max;
    }

    public static int cookingQuanttiyAndReduce(Recipe.Material[] materials, int expected, int[] materialCount) {
        int max = expected, t;
        int length = materials.length;
        for (int i = 0; i < length; i++) {
            Recipe.Material material = materials[i];
            t = cacheResult[materialCount[material.material]][material.quantity];
            max = t < max ? t : max;
            materialCount[material.material] -= material.quantity* max;
        }
        return max;
    }

    public int[] getFinalMaterialCount() {
        return materialCount.clone();
    }


    public void setMaterialCount(int[] materialCount) {
        this.materialCount = materialCount;
    }

    public void setExtraLimit(int[] extraLimit) {
        this.extraLimit = extraLimit;
    }
}
